/**
  ******************************************************************************
  * @file    Libraries/Device/TS32F020D/TS32F020D_LL_Driver/src/ts32f020d_ll_adc.c
  * @author  JUSHENG Application Team
  * @version V1.0.0
  * @date    02-19-2022
  * @brief   This file contains all the ADC LL firmware functions.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT 2022 JUSHENG</center></h2>
  *
  *
  *
  ******************************************************************************
  */ 

/* Includes ------------------------------------------------------------------*/
#include "include.h"

/** @addtogroup TS32F020D_StdPeriph_Driver TS32F020D Driver
  * @{
  */
  
/** @defgroup adc_interface_gr ADC Driver
  * @ingroup  TS32F020D_StdPeriph_Driver
  * @{
  */

/** @addtogroup ADC_LL_Driver ADC LL Driver
  * @ingroup  adc_interface_gr
  * @{
  */
  
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/** @defgroup ADC_LL_Inti_Cfg ADC LL Initialization And Configuration
  * @ingroup  ADC_LL_Driver
  * @brief    ADC LL Initialization And Configuration
  * @{
  */

/**
  * @brief  Low layer adc once mode init function
  * @param  p_adc: ponit of adc
  * @param  p_init : Configure the adc initialization structure
  * @retval None
  */
void ll_adc_once_init(ADC_TypeDef *p_adc, TYPE_LL_ADC_INIT *p_init)
{
    u32 adc_cfg = 0;

    p_adc->STA = ALL_WORD_FF;
    p_adc->CHS = LL_ADC_CHS_EN(p_init->channel_map);

    if(p_init->data_align)
    {
        p_adc->CR |= LL_ADC_CR_ALIGN;
    }
    else
    {
        p_adc->CR &= ~(LL_ADC_CR_ALIGN);
    }

    adc_cfg = p_adc->CFG;
    if(p_init->vcc_voltage)
    {
        adc_cfg |= LL_ADC_CFG_VOLTAGE_SEL;
    }
    else
    {
        adc_cfg &= ~(LL_ADC_CFG_VOLTAGE_SEL);
    }
    adc_cfg = (adc_cfg & ~(LL_ADC_CFG_REF_VOLTAGE_SEL(ALL_WORD_FF))) | LL_ADC_CFG_REF_VOLTAGE_SEL(p_init->ref_voltage);
    adc_cfg = (adc_cfg & ~(LL_ADC_CFG_D2DCYC(ALL_WORD_FF))) | LL_ADC_CFG_D2DCYC(p_init->interval_period);
    adc_cfg = (adc_cfg & ~(LL_ADC_CFG_PSC(ALL_WORD_FF))) | LL_ADC_CFG_PSC(p_init->prescaler);
    adc_cfg |= LL_ADC_CFG_EN;
    adc_cfg |= LL_ADC_CFG_LDO_EN;
    p_adc->CFG = adc_cfg;
    
    switch((ADC->CFG & 0x0e)>>1) //[1]: VOL_SEL, [3:2]: VREF_SEL
    {
        case 0x0 : 
        case 0x1 : ADC->BOUND = LL_ADC_BOUND_VSEL_2V;   break;
        case 0x2 :
        case 0x3 : ADC->BOUND = LL_ADC_BOUND_VSEL_2_5V; break;
        case 0x4 : ADC->BOUND = LL_ADC_BOUND_VSEL_4_5V; break;
        case 0x6 : ADC->BOUND = LL_ADC_BOUND_VSEL_5_0V; break;
        case 0x5 : 
        case 0x7 : ADC->BOUND = LL_ADC_BOUND_VSEL_3_3V; break;
    }
    delay_us(10);
}


/**
  * @brief  Low layer adc dma mode init function
  * @param  p_adc: ponit of adc
  * @param  p_init : Configure the adc initialization structure
  * @retval None
  */
void ll_adc_init(ADC_TypeDef *p_adc, TYPE_LL_ADC_INIT *p_init)
{
    u32 adc_cfg = 0;

    p_adc->STA = ALL_WORD_FF;
    p_adc->CHS = LL_ADC_CHS_EN(p_init->channel_map);

    p_adc->DMAADR = LL_ADC_DMAADDR_ADC_SET(p_init->dma_addr);
    p_adc->DMALEN = LL_ADC_DMALEN_DMA_LEN(p_init->dma_len - 1);
    p_adc->CR |= LL_ADC_CR_DMA_EN;

    if(p_init->scan_direction)
    {
        p_adc->CR |= LL_ADC_CR_SCAN_DIR;
    }
    else
    {
        p_adc->CR &= ~(LL_ADC_CR_SCAN_DIR);
    }
    if(p_init->data_align)
    {
        p_adc->CR |= LL_ADC_CR_ALIGN;
    }
    else
    {
        p_adc->CR &= ~(LL_ADC_CR_ALIGN);
    }

    adc_cfg = p_adc->CFG;
    if(p_init->vcc_voltage)
    {
        adc_cfg |= LL_ADC_CFG_VOLTAGE_SEL;
    }
    else
    {
        adc_cfg &= ~(LL_ADC_CFG_VOLTAGE_SEL);
    }
    adc_cfg = (adc_cfg & ~(LL_ADC_CFG_REF_VOLTAGE_SEL(ALL_WORD_FF))) | LL_ADC_CFG_REF_VOLTAGE_SEL(p_init->ref_voltage);
    adc_cfg = (adc_cfg & ~(LL_ADC_CFG_D2DCYC(ALL_WORD_FF))) | LL_ADC_CFG_D2DCYC(p_init->interval_period);
    adc_cfg = (adc_cfg & ~(LL_ADC_CFG_PSC(ALL_WORD_FF))) | LL_ADC_CFG_PSC(p_init->prescaler);
    adc_cfg |= LL_ADC_CFG_EN;
    adc_cfg |= LL_ADC_CFG_LDO_EN;
    p_adc->CFG = adc_cfg;
    
    switch((ADC->CFG & 0x0e)>>1) //[1]: VOL_SEL, [3:2]: VREF_SEL
    {
        case 0x0 : 
        case 0x1 : ADC->BOUND = LL_ADC_BOUND_VSEL_2V;   break;
        case 0x2 :
        case 0x3 : ADC->BOUND = LL_ADC_BOUND_VSEL_2_5V; break;
        case 0x4 : ADC->BOUND = LL_ADC_BOUND_VSEL_4_5V; break;
        case 0x6 : ADC->BOUND = LL_ADC_BOUND_VSEL_5_0V; break;
        case 0x5 : 
        case 0x7 : ADC->BOUND = LL_ADC_BOUND_VSEL_3_3V; break;
    }
    delay_us(10);
}

/**
  * @brief  Low layer adc External trigger config function
  * @param  p_adc: ponit of adc
  * @param  p_init : External trigger Configure the structure
  * @retval None
  */
void ll_adc_external_trigger_config(ADC_TypeDef *p_adc, TYPE_LL_ADC_EXT_TRG_CONFIG *p_init)
{
    p_adc->CR = (p_adc->CR & ~(LL_ADC_CR_TRG_DLY(ALL_WORD_FF))) | LL_ADC_CR_TRG_DLY(p_init->ext_trg_delay);
    p_adc->CR = (p_adc->CR & ~(LL_ADC_CR_TRG_SEL(ALL_WORD_FF))) | LL_ADC_CR_TRG_SEL(p_init->ext_trg_source);
    p_adc->CR |= LL_ADC_CR_EXT_TRG_EN;
}

/**
  * @brief  Low layer adc set channel map function
  * @param  channel: channel map
  * @retval None
  */
void ll_adc_set_channel_map(u32 channel)
{
    ADC->CHS = LL_ADC_CHS_EN(channel);
}

/**
  * @brief  Low layer adc set dma addr function
  * @param  addr: dma addr
  * @retval None
  */
void ll_adc_set_dma_addr(u32 addr)
{
    ADC->DMAADR = LL_ADC_DMAADDR_ADC_SET(addr);
}

/**
  * @}
  */

/** @defgroup ADC_LL_Data_Transfers ADC LL Data transfers functions
  * @ingroup  ADC_LL_Driver
  * @brief    ADC LL Data transfers functions 
  * @{
  */

/**
  * @brief  Low layer adc interrupt enable function
  * @param  None
  * @retval None
  */
void ll_adc_interrupt_enable(void)
{
    ADC->CR |= LL_ADC_CR_IE;
}

/**
  * @brief  Low layer adc interrupt disable function
  * @param  None
  * @retval None
  */
void ll_adc_interrupt_disable(void)
{
    ADC->CR &= ~LL_ADC_CR_IE;
}

/**
  * @brief  Low layer adc over run interrupt enable function
  * @param  None
  * @retval None
  */
void ll_adc_ovr_interrupt_enable(void)
{
    ADC->CR |= LL_ADC_CR_OVR_IE;
}

/**
  * @brief  Low layer adc over run interrupt disable function
  * @param  None
  * @retval None
  */
void ll_adc_ovr_interrupt_disable(void)
{
    ADC->CR &= ~LL_ADC_CR_OVR_IE;
}

/**
  * @brief  Low layer adc dma full interrupt enable function
  * @param  None
  * @retval None
  */
void ll_adc_dma_full_interrupt_enable(void)
{
    ADC->CR |= LL_ADC_CR_DMA_FULL_IE;
}

/**
  * @brief  Low layer adc dma full interrupt disable function
  * @param  None
  * @retval None
  */
void ll_adc_dma_full_interrupt_disable(void)
{
    ADC->CR &= ~LL_ADC_CR_DMA_FULL_IE;
}

/**
  * @brief  Low layer adc dma half full interrupt enable function
  * @param  None
  * @retval None
  */
void ll_adc_dma_half_full_interrupt_enable(void)
{
    ADC->CR |= LL_ADC_CR_DMA_HALF_IE;
}

/**
  * @brief  Low layer adc dma half full interrupt disable function
  * @param  None
  * @retval None
  */
void ll_adc_dma_half_full_interrupt_disable(void)
{
    ADC->CR &= ~LL_ADC_CR_DMA_HALF_IE;
}

/**
  * @brief  Low layer adc enable function
  * @param  None
  * @retval None
  */
void ll_adc_enable(void)
{
    ADC->CFG |= LL_ADC_CFG_EN;
}

/**
  * @brief  Low layer adc disable function
  * @param  None
  * @retval None
  */
void ll_adc_disable(void)
{
    ADC->CFG &= ~LL_ADC_CFG_EN;
}

/**
  * @brief  Low layer adc ldo enable function
  * @param  None
  * @retval None
  */
void ll_adc_ldo_enable(void)
{
    ADC->CFG |= LL_ADC_CFG_LDO_EN;
}

/**
  * @brief  Low layer adc ldo disable function
  * @param  None
  * @retval None
  */
void ll_adc_ldo_disable(void)
{
    ADC->CFG &= ~LL_ADC_CFG_LDO_EN;
}

/**
  * @brief  Low layer adc hardware data calibrate enable function
  * @param  None
  * @retval None
  */
void ll_adc_hardword_calibrate_enable(void)
{
    ADC->CR |= LL_ADC_CR_CAL_EN;
}

/**
  * @brief  Low layer adc hardware data calibrate disable function
  * @param  None
  * @retval None
  */
void ll_adc_hardword_calibrate_disable(void)
{
    ADC->CR &= ~LL_ADC_CR_CAL_EN;
}

/**
  * @brief  Low layer adc dma enable function
  * @param  None
  * @retval None
  */
void ll_adc_dma_enable(void)
{
    ADC->CR |= LL_ADC_CR_DMA_EN;
}

/**
  * @brief  Low layer adc dma disable function
  * @param  None
  * @retval None
  */
void ll_adc_dma_disable(void)
{
    ADC->CR &= ~LL_ADC_CR_DMA_EN;
}

/**
  * @brief  Low layer adc external interrupt source enable function
  * @param  None
  * @retval None
  */
void ll_adc_ext_trg_src_enable(void)
{
    ADC->CR |= LL_ADC_CR_EXT_TRG_EN;
}

/**
  * @brief  Low layer adc external interrupt source disable function
  * @param  None
  * @retval None
  */
void ll_adc_ext_trg_src_disable(void)
{
    ADC->CR &= ~LL_ADC_CR_EXT_TRG_EN;
}

/**
  * @brief  Low layer adc dma enable function
  * @param  None
  * @retval None
  */
void ll_adc_start_enable(void)
{
    ADC->CR |= LL_ADC_CR_KST;
}

/**
  * @brief  Low layer adc dma disable function
  * @param  None
  * @retval None
  */
void ll_adc_start_disable(void)
{
    ADC->CR &= ~LL_ADC_CR_KST;
}

/**
  * @brief  Low layer adc config
  * @param  ext_trg_source: Enumeration constant for low layer ADC trgsel
  * @param  ext_trg_delay: Enumeration constant for low layer ADC scan mode
  * @retval None
  */
void ll_adc_trgsel_config( TYPE_ENUM_LL_ADC_TRG_SEL ext_trg_source,  TYPE_ENUM_LL_ADC_TRG_SHIFT ext_trg_delay)
{
    u32 adc_temp = 0;
    adc_temp = ADC->CR;
    adc_temp = (adc_temp &(~LL_ADC_CR_TRG_SEL(ALL_WORD_FF))) | LL_ADC_CR_TRG_SEL(ext_trg_source);
    adc_temp = (adc_temp &(~LL_ADC_CR_TRG_DLY(ALL_WORD_FF))) | LL_ADC_CR_TRG_DLY(ext_trg_delay);
    
    ADC->CR = adc_temp;
    ADC->CR |= LL_ADC_CR_EXT_TRG_EN;
}

/**
  * @brief  Low layer adc config
  * @param  ref_vol: Select ADC reference voltage 
  * @retval None
  */
void ll_adc_config(TYPE_ENUM_LL_ADC_VSEL ref_vol)
{
    u32 adc_temp = 0;
    
    ADC->CR &= ~LL_ADC_CR_DMA_EN; //close adc dma
    ADC->CR |= LL_ADC_CR_ALIGN;   //default right alignment
    
    adc_temp = ADC->CFG;
    adc_temp = (adc_temp &(~LL_ADC_CFG_REF_VOLTAGE_SEL(ALL_WORD_FF))) | LL_ADC_CFG_REF_VOLTAGE_SEL(ref_vol);
    adc_temp = (adc_temp & (~LL_ADC_CFG_D2DCYC(ALL_WORD_FF))) | LL_ADC_CFG_D2DCYC(0xFF);
    adc_temp = (adc_temp & (~LL_ADC_CFG_PSC_MASK)) | LL_ADC_CFG_PSC(0xF) | LL_ADC_CFG_LDO_EN | LL_ADC_CFG_EN;
    ADC->CFG = adc_temp;

    switch((ADC->CFG & 0x0e)>>1) //[1]: VOL_SEL, [3:2]: VREF_SEL
    {
        case 0x0 : 
        case 0x1 : ADC->BOUND = LL_ADC_BOUND_VSEL_2V;   break;
        case 0x2 :
        case 0x3 : ADC->BOUND = LL_ADC_BOUND_VSEL_2_5V; break;
        case 0x4 : ADC->BOUND = LL_ADC_BOUND_VSEL_4_5V; break;
        case 0x6 : ADC->BOUND = LL_ADC_BOUND_VSEL_5_0V; break;
        case 0x5 : 
        case 0x7 : ADC->BOUND = LL_ADC_BOUND_VSEL_3_3V; break;
    }
    
    ADC->STA = (ADC->STA & (~LL_ADC_STA_DONE));
    delay_us(10);
    
}

/**
  * @brief  Low layer adc config
  * @param  ref_vol: Select ADC reference voltage 
  * @param  channel_map: channel bit map (ex:LL_ADC_CHS_0--LL_ADC_CHS_25) 
  * @param  dma_addr: Select ADC dma address 
  * @retval None
  */
void ll_adc_multi_config(TYPE_ENUM_LL_ADC_VSEL ref_vol, u32 channel_map, u16* dma_addr)
{
    u32 adc_temp = 0;
    
    ll_adc_config(ref_vol);
    ADC->CHS = channel_map & 0x3FFFFFF;
    for(u8 i=0; i<26; i++)
    {
        if(((channel_map) >> i)&0x1)
            adc_temp++;
    }
    ADC->DMALEN = adc_temp - 1;
    ADC->DMAADR = (u32)dma_addr;
    ADC->CR |= LL_ADC_CR_ALIGN | LL_ADC_CR_DMA_EN; //default right alignment and dma enable
}

/**
  * @brief  Adc data get
  * @param  None
  * @retval None
  */
void ll_adc_data_get(void)
{
    ADC->CR |= LL_ADC_CR_KST;
    while(!(LL_ADC_DONE_PEND_GET()));        //wait for pending
    LL_ADC_DONE_PEND_CLR();                  //clear pending
}

/**
  * @brief  Get adc channel sample result 
  * @param  adc_channel: ADC input channel enable
  * @retval None
  */
u16 ll_adc_channel_sample_get(u32  adc_channel)
{
    ADC->CHS = LL_ADC_CHS_EN(adc_channel);
    ll_adc_data_get();
    return (((ADC->DATA)>>0) & 0xFFF);
}



/**
  * @}
  */

/**
  * @}
  */

/**
  * @}
  */

/**
  * @}
  */

/*************************** (C) COPYRIGHT 2022 JUSHENG ***** END OF FILE *****/
